// 防抖函数
export const deBounce = (fn, wait) => {
    let timer;
    return function () {
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(() => {
            fn.apply(this, arguments);
        }, wait);
    };
};
// 深拷贝
export const deepClone = (obj, hash = new WeakMap()) => {
    // 如果传入的是值类型/null，直接返回
    if (typeof obj !== 'object' || obj === null) return obj;

    // 处理过的值直接返回-处理循环引用
    if (hash.get(obj)) return hash.get(obj);

    let result = obj instanceof Array ? [] : {};
    hash.set(obj, result);
    for (const key in obj) {
        if (Object.hasOwnProperty.call(obj, key)) {
            result[key] = deepClone(obj[key], hash);
        }
    }
    return result;
};

/**
 * 节流器
 * @param {Function} fun 功能函数
 * @param {Number} delay 节流间隔
 * @returns {Function} 经节流器包装后生成的新函数, 其参数同 fun
 */
export const throttle = (fun, delay) => {
    let last, deferTimer;
    return (...args) => {
        const argsCopy = args;
        const now = new Date();
        let intervalTime;
        if (last) {
            intervalTime = now - last;
        } else {
            intervalTime = 0;
        }
        if (intervalTime < delay) {
            clearTimeout(deferTimer);
            deferTimer = setTimeout(() => {
                last = now;
                fun.apply(this, argsCopy);
            }, delay);
        } else {
            last = now;
            fun.apply(this, argsCopy);
        }
    };
};

/**
 * 返回js数据类型
 * @param {*} obj
 * @returns {String} js数据类型
 */
export const getDataType = obj => {
    // tostring会返回对应不同的标签的构造函数
    const { toString } = Object.prototype;
    const map = {
        '[object Boolean]': 'boolean',
        '[object Number]': 'number',
        '[object String]': 'string',
        '[object Function]': 'function',
        '[object Array]': 'array',
        '[object Date]': 'date',
        '[object RegExp]': 'regExp',
        '[object Undefined]': 'undefined',
        '[object Null]': 'null',
        '[object Object]': 'object'
    };
    if (obj instanceof Element) {
        return 'element';
    }
    return map[toString.call(obj)];
};

// 数字补零
export const addZero = val => {
    return val.toString().padStart(2, '0');
};
/**
 * 获取当前时间
 * @return {string}
 */
export const getTimeNow = () => {
    const D = new Date();
    const year = D.getFullYear();
    const mouth = D.getMonth() + 1;
    const day = D.getDate();
    const hour = D.getHours();
    const minute = D.getMinutes();
    const second = D.getSeconds();
    return `${year}-${addZero(mouth)}-${addZero(day)} ${addZero(
        hour
    )}:${addZero(minute)}:${addZero(second)}`;
};
/**
 * 生产随机字符串
 * @param {String} len 生成的字符串长度
 * @returns {String}
 */
export const randomString = (len = 10) => {
    const $chars =
            'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890',
        maxPos = $chars.length;
    let pwd = '';
    for (let i = 0; i < len; i++) {
        pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
    }
    return pwd;
};

/**
 * 格式化 日期的方法
 * @param {Date | String | Number | timestamp} date
 * @param {String} fmt  "yyyy-MM-dd hh:mm:ss.S" ==> 2006-07-02 08:09:04.423 ;   "yyyy-M-d h:m:s.S" ==> 2006-7-2 8:9:4.18
 * @returns {String}
 */
export const formatDate = (date, fmt) => {
    if (Object.prototype.toString.call(date) !== '[object Date]') {
        date = new Date(date);
    }
    const o = {
        'M+': date.getMonth() + 1, // 月份
        'd+': date.getDate(), // 日
        'h+': date.getHours(), // 小时
        'm+': date.getMinutes(), // 分
        's+': date.getSeconds(), // 秒
        'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
        S: date.getMilliseconds() // 毫秒
    };
    if (/(y+)/.test(fmt)) {
        fmt = fmt.replace(
            RegExp.$1,
            `${date.getFullYear()}`.substr(4 - RegExp.$1.length)
        );
    }
    for (const k in o) {
        if (new RegExp(`(${k})`).test(fmt)) {
            fmt = fmt.replace(
                RegExp.$1,
                RegExp.$1.length === 1
                    ? o[k]
                    : `00${o[k]}`.substr(`${o[k]}`.length)
            );
        }
    }
    return fmt;
};

/**
 * 判断是否为空值  注意 0 为非空值
 * @param {*} value
 * @returns Boolean
 */
export const isEmpty = value => {
    if (value !== 0 && !value) {
        return true;
    }
    return (
        Object.prototype.toString.call(value) === '[object Array]' &&
        !value.length
    );
};

/**
 * 获取url？后面的字符串
 * @returns {Object}
 */
export const getUrlParams = () => {
    const url = window.location.href.split('?')[1], // 获取url中"?"符后的字串
        theRequest = {};
    if (url) {
        const strs = url.split('&');
        for (let i = 0; i < strs.length; i++) {
            theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1]);
        }
    }
    return theRequest;
};

/**
 * 获取窗口视图高度
 *
 * @returns {number}
 */
export const getClientHeight = () => {
    let clientHeight;
    const isBodyOrElementClientHeight =
        document.body.clientHeight && document.documentElement.clientHeight;
    if (isBodyOrElementClientHeight) {
        clientHeight =
            document.body.clientHeight < document.documentElement.clientHeight
                ? document.body.clientHeight
                : document.documentElement.clientHeight;
    } else {
        clientHeight =
            document.body.clientHeight > document.documentElement.clientHeight
                ? document.body.clientHeight
                : document.documentElement.clientHeight;
    }
    return clientHeight;
};

/**
 * 获取操作平台判断 mac or windows
 * @returns {{isWindows32: boolean, isMac: boolean, isWindows64: boolean, isWindows: boolean}}
 */
export const getOsInfo = () => {
    const agent = navigator.userAgent.toLowerCase();
    const isMac = /macintosh|mac os x/i.test(navigator.userAgent);

    const isWindows32 =
        agent.indexOf('win32') >= 0 || agent.indexOf('wow32') >= 0;
    const isWindows64 =
        agent.indexOf('win64') >= 0 || agent.indexOf('wow64') >= 0;

    return {
        isMac: isMac,
        isWindows32: isWindows32,
        isWindows64: isWindows64,
        isWindows: isWindows32 || isWindows64
    };
};
/**
 * @description 下载文件
 * @param obj {file} 文件流
 */
export function downloadFile({ file, fileName }) {
    const url = URL.createObjectURL(
        new Blob([file], { type: 'application/zip' })
    );
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    a.download = fileName;
    document.body.appendChild(a);
    a.click();
    URL.revokeObjectURL(url);
    document.body.removeChild(a);
}

/**
 * @description 高亮关键词
 * @param {String} str 源文本
 * @param {String} keyword 需要高亮的关键词
 * @param {String} color 高亮颜色
 * @returns {String}
 */
export function highLightWords(str, keyword, color = '#246FE5') {
    let res = str;
    let replaceReg = new RegExp(keyword, 'ig');
    let val = str.match(replaceReg);
    if (val) {
        let replaceString = `<span style="color: ${color}">${val[0]}</span>`;
        res = str.replace(replaceReg, replaceString);
    }
    return res;
}

/**
 * 点击弹窗外层
 * @param {Event} e event对象
 * @param {HTMLElement | HTMLDivElement} dom 监听的dom对象
 * @param {Function} cb 回调
 */
export const clickOutside = (e, dom, cb) => {
    if (!dom?.contains(e.target)) cb();
};

// 平铺树
export const tileTree = (tree, props, parentId = null, result = []) => {
    const treeCopy = deepClone(tree);
    const propsCopy = {
        id: 'id',
        children: 'children',
        ...props
    };
    treeCopy.forEach(item => {
        item.parentId = parentId;
        result.push(item);
        if (item[propsCopy.children]?.length)
            tileTree(item.children, propsCopy, item[propsCopy.id], result);
    });
    return result;
};
